#ifndef Event_INCLUDED
#define Event_INCLUDED

#include <pthread.h>
#include <errno.h>
#include <sys/time.h>

class Event
    /// equals to a condition variable
{
public:
    Event(bool autoReset = true);

    ~Event();

    void set();
        /// Signals the event.

    void wait();
        /// Waits for the event to become signalled.

    bool wait(long milliseconds);
        /// true 表示没有超时

    bool tryWait(long milliseconds);
        /// true 表示没有超时

    void reset();
        /// Resets the event to unsignalled state.
    
private:
    Event(const Event&);
    Event& operator = (const Event&);
    
private:
    bool            m_autoReset;
    volatile bool   m_state;
    pthread_mutex_t m_mutex;
    pthread_cond_t  m_cond;
};


//
// inlines
//
inline void Event::set()
{
    pthread_mutex_lock(&m_mutex);
    m_state = true;
    pthread_cond_broadcast(&m_cond);
    pthread_mutex_unlock(&m_mutex);
}


inline void Event::wait()
{
    pthread_mutex_lock(&m_mutex);
    while (!m_state)
    {
        if (pthread_cond_wait(&m_cond, &m_mutex))
            break;
    }
    if (m_autoReset)
        m_state = false;
    
    pthread_mutex_unlock(&m_mutex);
}


inline bool Event::wait(long milliseconds)
{
    int rc = 0;
    struct timespec abstime;
    struct timeval tv;
    gettimeofday(&tv, NULL);
    int nsec = milliseconds/1000;
    abstime.tv_sec  = tv.tv_sec + nsec;
    abstime.tv_nsec = tv.tv_usec*1000 + (milliseconds % 1000)*1000000;
    if (abstime.tv_nsec >= 1000000000)
    {
        abstime.tv_nsec -= 1000000000;
        abstime.tv_sec++;
    }
    
    pthread_mutex_lock(&m_mutex);
    while (!m_state) 
    {
        if ((rc = pthread_cond_timedwait(&m_cond, &m_mutex, &abstime)))
        {
            if (rc == ETIMEDOUT) break;
        }
    }
   
    if (rc == 0 && m_autoReset)
        m_state = false;
    
    pthread_mutex_unlock(&m_mutex);
    
    return rc == 0;
}


inline bool Event::tryWait(long milliseconds)
{
    return wait(milliseconds);
}


inline void Event::reset()
{
    pthread_mutex_lock(&m_mutex);
    m_state = false;
    pthread_mutex_unlock(&m_mutex);
}

#endif



